package jsu.hx.lost.Service;

import com.alibaba.excel.EasyExcel;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import jsu.hx.lost.Mapper.FindMapper;
import jsu.hx.lost.Mapper.LostMapper;
import jsu.hx.lost.Model.dto.LostItemDTO;
import jsu.hx.lost.Model.entity.FindItem;
import jsu.hx.lost.Model.dto.FindItemDTO;
import jsu.hx.lost.Model.entity.LostItem;
import jsu.hx.lost.Model.entity.Notifications;
import jsu.hx.lost.Model.vo.PageResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;

@Slf4j
@Service
public class FindItemService  {

    @Autowired
    private FindMapper findMapper;

    @Autowired
    private FileStorageService fileStorageService;
    @Autowired
    private LostMapper lostMapper;
    @Autowired
    private NotificationsService notificationsService;
    public List<FindItemDTO> getAllFindItems() {
        return findMapper.selectFindItemDTOs();
    }

    public FindItemDTO getFindItemById(Long id) {
        return findMapper.selectFindItemDTOById(id);
    }

    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> addFindItem(String itemName, String itemCategory, String foundLocation,String locate,
                                           Date foundTime, String detailedDescription, MultipartFile imageFile) {
        Map<String, Object> response = new HashMap<>();
        try {
            Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
            if (authentication == null || authentication.getPrincipal() == null) {
                response.put("status", "error");
                response.put("message", "用户未认证");
                return response;
            }

            Long userId = Long.parseLong(authentication.getPrincipal().toString());
            String imagePath = null;

            // 取消默认图片设置，如果没有上传图片，imagePath为null
            if (imageFile != null && !imageFile.isEmpty()) {
                imagePath = fileStorageService.saveImage(imageFile, "find_items");
            }

            FindItem findItem = buildFindItem(userId, itemName, itemCategory, foundLocation,locate,
                    foundTime, detailedDescription, imagePath);

            int result = findMapper.insert(findItem);
            if (result > 0) {
                checkLostItemMatches(findItem);
                response.put("status", "success");
                response.put("data", findItem.getId()); // 返回新创建的物品ID
                response.put("message", "物品添加成功");
            } else {
                response.put("status", "error");
                response.put("message", "数据库插入失败");
            }
        } catch (Exception e) {
            handleException(response, e);
        }
        return response;
    }

    // 统一异常处理方法
    private void handleException(Map<String, Object> response, Exception e) {
        response.put("status", "error");
        if (e instanceof NumberFormatException) {
            response.put("message", "无效的用户凭证");
        } else if (e instanceof IllegalArgumentException) {
            response.put("message", e.getMessage());
        } else if (e instanceof IOException) {
            response.put("message", "图片保存失败: " + e.getMessage());
        } else {
            log.error("添加物品时发生未知错误", e);
            response.put("message", "服务器内部错误");
        }
    }

    // 私有方法：构建FindItem对象
    private FindItem buildFindItem(Long userId, String itemName, String itemCategory, String foundLocation,String locate,
                                   Date foundTime, String detailedDescription, String imagePath) {
        FindItem findItem = new FindItem();
        findItem.setUserId(userId);
        findItem.setItemName(itemName);
        findItem.setItemCategory(itemCategory);
        findItem.setFoundLocation(foundLocation);
        findItem.setLocate(locate);
        findItem.setFoundTime(foundTime);
        findItem.setDetailedDescription(detailedDescription);
        findItem.setImage(imagePath); // 可能为null
        findItem.setAddTime(new Date());
        findItem.setIsDeleted(0);
        return findItem;
    }


    @Transactional
    public Map<String, Object> updateFindItem(Long id, MultipartFile imageFile, String itemName,
                                              String itemCategory, String foundLocation,String locate, Date foundTime,
                                              String detailedDescription) {
        Map<String, Object> response = new HashMap<>();
        String newImagePath = null;
        String oldImagePath = null;

        try {
            // 1. 获取原数据
            FindItem existingItem = findMapper.selectById(id);
            if (existingItem == null || existingItem.getIsDeleted() == 1) {
                response.put("status", "error");
                response.put("message", "指定ID的记录不存在");
                return response;
            }
            oldImagePath = existingItem.getImage();

            // 2. 文件上传（优先处理）
            if (imageFile != null && !imageFile.isEmpty()) {
                newImagePath = fileStorageService.saveImage(imageFile, "find_items");
            }

            // 3. 构建动态更新条件
            UpdateWrapper<FindItem> wrapper = new UpdateWrapper<FindItem>().eq("id", id);

            // 4. 字段更新逻辑
            // 字符串字段：空字符串和null不更新
            updateField(wrapper, "item_name", itemName, existingItem.getItemName());
            updateField(wrapper, "item_category", itemCategory, existingItem.getItemCategory());
            updateField(wrapper, "found_location", foundLocation, existingItem.getFoundLocation());
            updateField(wrapper, "detailed_description", detailedDescription, existingItem.getDetailedDescription());
            updateField(wrapper, "locate", locate, existingItem.getLocate());
            // 时间字段：允许设置为null
            if (foundTime != null) {
                wrapper.set("found_time", foundTime);
            }

            // 图片路径更新
            if (newImagePath != null) {
                wrapper.set("image", newImagePath);
            }

            // 5. 执行数据库更新
            int result = findMapper.update(null, wrapper);

            if (result > 0) {
                // 6. 成功时删除旧图片（保留默认图片）
                if (newImagePath != null && oldImagePath != null && !oldImagePath.isEmpty()) {
                    safeDeleteFile(oldImagePath);
                }
                response.put("status", "success");
                response.put("data", findMapper.selectById(id));
            } else {
                // 7. 数据库失败时回滚新图片
                safeDeleteFile(newImagePath);
                response.put("status", "error");
                response.put("message", "更新操作未生效");
            }
        } catch (Exception e) {
            // 8. 异常时回滚新图片
            safeDeleteFile(newImagePath);
            handleException(response, e);
        }
        return response;
    }

    // 辅助方法：字段更新逻辑
    private void updateField(UpdateWrapper<FindItem> wrapper, String column, String newValue, String originalValue) {
        if (newValue != null) {
            // 空字符串不更新，非空字符串且与原值不同时更新
            if (StringUtils.hasText(newValue) && !newValue.equals(originalValue)) {
                wrapper.set(column, newValue);
            }
        }
    }

    // 安全删除文件（带异常捕获）
    private void safeDeleteFile(String filePath) {
        if (filePath != null && !filePath.isEmpty()) {
            try {
                fileStorageService.deleteOldImage(filePath);
            } catch (IOException e) {
                log.error("文件删除失败: {}", e.getMessage());
            }
        }
    }


    @Transactional
    public String deleteFindItem(Long id) {
        UpdateWrapper<FindItem> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id", id)
                .set("is_deleted", 1);
        int result = findMapper.update(null, updateWrapper);
        return result > 0 ? "Item deleted successfully" : "Failed to delete item";
    }

    public Map<String, Object> getMyFindItems() {
        Map<String, Object> response = new HashMap<>();
        try {
            Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
            if (authentication == null || authentication.getPrincipal() == null) {
                response.put("status", "error");
                response.put("message", "用户未认证");
                return response;
            }

            Long currentUserId = Long.parseLong(authentication.getPrincipal().toString());
            List<FindItemDTO> items = findMapper.selectFindItemDTOsByUserId(currentUserId);

            response.put("status", "success");
            response.put("data", items);
        } catch (NumberFormatException e) {
            response.put("status", "error");
            response.put("message", "无效的用户凭证");
        } catch (Exception e) {
            log.error("查询用户物品失败: {}", e.getMessage());
            response.put("status", "error");
            response.put("message", "服务器错误");
        }
        return response;
    }

    public List<FindItemDTO> fuzzySearch(String itemName, String foundLocation, Date foundTime, String username) {
        return findMapper.selectByFuzzySearch(itemName, foundLocation, foundTime, username); // 添加新参数
    }

    public PageResult<FindItemDTO> getFindItemsByPage(int page, int pageSize, String itemName,
                                                      String foundLocation, Date foundTime, String username,
                                                      String sortField, String sortOrder) {
        // 参数校验
        if (page < 1) page = 1;
        if (pageSize < 1) pageSize = 10;
        int offset = (page - 1) * pageSize;

        // 校验排序字段合法性
        Set<String> allowedSortFields = new HashSet<>(Arrays.asList("id", "found_time", "addtime")); // 添加创建时间排序
        if (!allowedSortFields.contains(sortField.toLowerCase())) {
            sortField = "id";
        }

        // 校验排序方向
        if (!"ASC".equalsIgnoreCase(sortOrder) && !"DESC".equalsIgnoreCase(sortOrder)) {
            sortOrder = "DESC";
        }

        // 查询分页数据（添加新参数）
        List<FindItemDTO> items = findMapper.selectFindItemDTOsByPage(offset, pageSize,
                itemName, foundLocation, foundTime, username, sortField, sortOrder);

        // 查询总记录数（添加新参数）
        long total = findMapper.selectFindItemTotalCount(itemName, foundLocation, foundTime, username);

        return new PageResult<>(items, total, page, pageSize);
    }

    public List<FindItemDTO> getLatestFoundItems(int limit) {
        return findMapper.selectLatestFoundItems(limit);
    }
    private void checkLostItemMatches(FindItem newFindItem) {
        // 调用 LostMapper 的模糊查询
        List<LostItemDTO> matches = lostMapper.selectByFuzzySearch(
                newFindItem.getItemName(),
                newFindItem.getFoundLocation(), // 对应 LostItem 的 lostLocation
                newFindItem.getFoundTime(),      // 对应 LostItem 的 lostTime
                null
        );

        // 过滤已存在的通知并创建新通知
        matches.stream()
                .filter(match -> !isNotificationExists(newFindItem.getUserId(), "LOST", newFindItem.getId()))
                .forEach(match -> createNotification(match, newFindItem));
    }

    private void createNotification(LostItemDTO lostItem, FindItem findItem) {
        Notifications notification = Notifications.builder()
                .userId(findItem.getUserId()) // 通知丢失物品的发布者
                .title("发现可能的丢失物品匹配")
                .content(String.format("您发布的【%s】招领信息可能与用户%s的丢失物品匹配",
                        findItem.getItemName(), lostItem.getUsername()))
                .relatedType("LOST")
                .relatedLostItemId(lostItem.getId()) // 关联到 LostItem 的 ID
                .build();
        saveNotification(notification);
    }

    private void saveNotification(Notifications notification) {
        if (notificationsService.getByRelatedItem(
                notification.getUserId(),
                notification.getRelatedType(),
                notification.getRelatedType().equals("LOST") ?
                        notification.getRelatedLostItemId() :
                        notification.getRelatedFoundItemId()
        ) == null) {
            // 调用 MyBatis-Plus 的 save 方法触发自动填充
            notificationsService.save(notification);
        }
    }

    private boolean isNotificationExists(Long userId, String type, Long itemId) {
        return notificationsService.getByRelatedItem(userId, type, itemId) != null;
    }
    public int importFromExcel(MultipartFile file) throws Exception {
        int count = 0;
        try (InputStream is = file.getInputStream()) {
            // 获取当前用户ID
            Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
            Long userId = Long.parseLong(authentication.getPrincipal().toString());

            List<FindItemDTO> dtos = EasyExcel.read(is)
                    .head(FindItemDTO.class)
                    .sheet()
                    .doReadSync();

            for (FindItemDTO dto : dtos) {
                Map<String, Object> result = addFindItem(
                        dto.getItemName(),
                        dto.getItemCategory(),
                        dto.getFoundLocation(),
                        dto.getLocate(),
                        dto.getFoundTime(),
                        dto.getDetailedDescription(),
                        null // 图片不导入
                );
                if ("success".equals(result.get("status"))) {
                    count++;
                }
            }
        }
        return count;
    }

    // 修改导出方法
    public ByteArrayOutputStream exportToExcel(List<FindItemDTO> items) throws Exception {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        EasyExcel.write(outputStream, FindItemDTO.class)
                .sheet("招领数据数据")
                .doWrite(items);
        return outputStream;
    }
}